package com.idea.relax.redis.config;

import com.idea.relax.redis.lock.config.RelaxRedisLockProperties;
import com.idea.relax.redis.lock.support.RedissonConfigBuilder;
import com.idea.relax.redis.support.proto.ProtoStuffSerializer;
import com.idea.relax.redis.support.spel.IExpressionEvaluator;
import com.idea.relax.redis.support.spel.RelaxExpressionEvaluator;
import com.idea.relax.redis.toolkit.RedisOps;
import lombok.AllArgsConstructor;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import static com.idea.relax.redis.config.SerializerType.*;

/**
 * @className: RedisAutoConfiguration
 * @description:
 * @author: salad
 * @date: 2022/9/6
 **/
@Configuration(
     proxyBeanMethods = false
)
@AllArgsConstructor
@AutoConfigureBefore({org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.class})
@EnableConfigurationProperties(RelaxRedisProperties.class)
public class RedisAutoConfiguration {

    private final RelaxRedisProperties redisProperties;

	@Bean(name = "expressionEvaluator")
	@ConditionalOnMissingBean(name = "expressionEvaluator")
	public IExpressionEvaluator expressionEvaluator() {
		return new RelaxExpressionEvaluator();
	}


	@Bean(name = "redisSerializer")
    @ConditionalOnMissingBean(name = "redisSerializer")
    public RedisSerializer<Object> redisSerializer(){
        if (PROTO_STUFF == redisProperties.getSerializerType()){
            return new ProtoStuffSerializer();
        }else if (JSON == redisProperties.getSerializerType()){
            return new GenericJackson2JsonRedisSerializer();
        }else {
            ClassLoader classLoader = getClass().getClassLoader();
            return new JdkSerializationRedisSerializer(classLoader);
        }
    }

    @Bean(name = {"redisTemplate"})
    @ConditionalOnMissingBean(name = {"redisTemplate"})
    public RedisTemplate<String, Object> redisTemplate(RedisSerializer<Object> redisSerializer,
                                                       RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(redisSerializer);
        template.setHashValueSerializer(redisSerializer);
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean(name = "redisOps")
    @ConditionalOnMissingBean(name = "redisOps")
    public RedisOps redisOps(RedisTemplate<String, Object> redisTemplate){
        return new RedisOps(redisTemplate);
    }

	@Bean
	@ConditionalOnBean()
	@ConditionalOnMissingBean(name = "redissonClient")
	public RedissonClient redissonClient(RelaxRedisLockProperties relaxRedisLockProperties) {
		return Redisson.create(RedissonConfigBuilder.build(relaxRedisLockProperties));
	}

}
